package com.wyl.niupi.framework.util;

import com.wyl.niupi.framework.util.http._HttpRequestUtil;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.*;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class _BeanUtil {

	static {
		// 防止BeanUtils.copyProperties 如果Integer 或Long 为null 默认赋值0
		// 参考博客：https://blog.csdn.net/linminqin/article/details/7929863
		ConvertUtils.register(new LongConverter(null), Long.class);
		ConvertUtils.register(new ShortConverter(null), Short.class);
		ConvertUtils.register(new IntegerConverter(null), Integer.class);
		ConvertUtils.register(new DoubleConverter(null), Double.class);
		ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
	}

	/**
	 * 从httpRequest里解析出属于dest的属性，然后将request里的属性赋值给desc。 </br>
	 * 主要用于简化修改操作，前台传什么属性就修改什么属性的值；对于前台没有传的属性，不会改变其值
	 *
	 * @param dest 目标对象
	 * @param request
	 * @author 吴宇亮
	 * @date 2019年1月8日
	 */
	public static <T> T copyPropertiesFromRequest(T dest, HttpServletRequest request) throws IllegalAccessException, InvocationTargetException {
		Field[] declaredFields = dest.getClass().getDeclaredFields();
		Map<String, String> requestMap = _HttpRequestUtil.getRequestMap(request);
		for (String key : requestMap.keySet()) {
			if (isHasField(declaredFields, key)) {
				BeanUtils.setProperty(dest, key, requestMap.get(key));
			}
		}
		return dest;
	}

	/**
	 * 将source的每个字段的值复制到dest中，如果source字段的值为null，则不进行复制。跳过被final或static修饰的属性
	 * @param dest 被设置数据的bean
	 * @param source 数据的来源bean
	 */
	public static <T> T copyPropertiesIgnoreNull(T dest, T source) throws IllegalAccessException {
		Field[] declaredFields = dest.getClass().getDeclaredFields();
		for (Field declaredField : declaredFields) {
			int modifiers = declaredField.getModifiers();
			if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)){
				continue;
			}
			declaredField.setAccessible(true);
			Object sourceValue = declaredField.get(source);
			if(null == sourceValue){
				continue;
			}
			declaredField.set(dest, sourceValue);
		}
		return dest;
	}

	/**
	 * 将source的每个字段的值复制到dest中。跳过被final或static修饰的属性
	 * @param dest 被设置数据的bean
	 * @param source 数据的来源bean
	 */
	public static <T> T copyProperties(T dest, T source) throws IllegalAccessException {
		Field[] declaredFields = dest.getClass().getDeclaredFields();
		for (Field declaredField : declaredFields) {
			int modifiers = declaredField.getModifiers();
			if (Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers)){
				continue;
			}
			declaredField.setAccessible(true);
			Object sourceValue = declaredField.get(source);
			declaredField.set(dest, sourceValue);
		}
		return dest;
	}

	/**
	 * 判断Class类型里是否含有field这个字段
	 *
	 * @param clazz 类型
	 * @param fieldName 字段名称
	 * @return
	 * @author 吴宇亮
	 * @date 2019年1月23日
	 */
	public static boolean isHasField(Class<?> clazz, String fieldName) {
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field field : declaredFields) {
			if(field.getName().equals(fieldName) ){
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断Field[]里是否含有field这个字段，有的话返回true；否则返回false
	 *
	 * @param declaredFields 字段数组
	 * @param fieldName 字段名称
	 * @return
	 * @author 吴宇亮
	 * @date 2019年1月23日
	 */
	public static boolean isHasField(Field[] declaredFields, String fieldName) {
		for (Field field : declaredFields) {
			if(field.getName().equals(fieldName) ){
				return true;
			}
		}
		return false;
	}

	/**
	 * 根据属性名称和java类型，获取对应的getter方法名
	 * 
	 * @param fieldName 字段名
	 */
	public static String getGetterMethodName(String fieldName) {
		StringBuilder sb = new StringBuilder(20);
		sb.append(fieldName);
		if (Character.isLowerCase(sb.charAt(0))) {
			if (sb.length() == 1 || !Character.isUpperCase(sb.charAt(1))) {
				sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
			}
		}
		sb.insert(0, "get");
		return sb.toString();
	}

	/**
	 * 根据属性名称获取对应的setter方法名称
	 * 
	 * @param fieldName 属性名称
	 */
	public static String getSetterMethodName(String fieldName) {
		StringBuilder sb = new StringBuilder(20);
		sb.append(fieldName);
		if (Character.isLowerCase(sb.charAt(0))) {
			if (sb.length() == 1 || !Character.isUpperCase(sb.charAt(1))) {
				sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
			}
		}
		sb.insert(0, "set");
		return sb.toString();
	}

	/**
	 * 下划线风格 转换成  骆驼峰风格。 <br/>
	 * 参考博客：https://youchenglin.iteye.com/blog/2102321
	 *
	 * @param str 带转字符串
	 * @author 吴宇亮
	 * @date 2019年1月9日
	 */
	public static String transform_2UpperCase(String str){
		while(str.contains("_")){
			int i = str.indexOf("_");
			if(i+1<str.length()){
				char c = str.charAt(i+1);
				String temp = (c+"").toUpperCase();
				str = str.replace("_"+c, temp);
			}
		}
		return str;
	}

	private static final Pattern compile = Pattern.compile("[A-Z]");
	/**
	 * 骆驼峰风格 转换成 下划线风格。 <br/>
	 * 参考博客：https://blog.csdn.net/fly_down/article/details/46471917
	 *
	 * @param str 带转字符串
	 * @author 吴宇亮
	 * @date 2019年1月9日
	 */
	public static String transformUpperCase2_(String str) {
		if(StringUtils.isBlank(str)){
			return str;
		}
		//首字母转换成小写
		str = str.substring(0, 1).toLowerCase() + str.substring(1);

		//转换
		Matcher matcher = compile.matcher(str);
		StringBuffer sb = new StringBuffer(str.length()+10);
		while(matcher.find()){
			matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

}
